package com.sztz.handle;

import cn.hutool.core.bean.BeanException;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Param;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 批量处理器
 * @author yzy
 * @date 2022/7/27 13:51
 */
@Slf4j
public class BatchProvider {
    /**
     * 批量插入,指定表名
     * @param list              插入的数据
     * @param tableName         数据库对应的表名
     * @return 拼装好的执行sql
     * @author yzy
     * @date 2022/7/27 16:58
     */
    public <T extends Serializable> String insertBatchOfTableName(@Param("list") List<T> list, String tableName) {
        if (CollUtil.isEmpty(list)) {
            throw new IllegalArgumentException("批量插入的数据不能为Empty");
        }
        if (StrUtil.isBlank(tableName)) {
            throw new IllegalArgumentException("数据库表名不能为空");
        }
        List<String> columnNameList = getColumnNames(list.get(0));
        StringBuilder sqlStr = new StringBuilder();
        sqlStr.append("INSERT INTO ").append(tableName).append(columnNameList.stream().collect(Collectors.joining(StrUtil.COMMA, "(", ") VALUES ")));
        String sqlStrOfValues = columnNameList.stream().map(StrUtil::toCamelCase).collect(Collectors.joining("},#'{'list[{0}].", "(#'{'list[{0}].", "}) "));
        MessageFormat mf = new MessageFormat(sqlStrOfValues);
        for (int i = 0, len = list.size(); i < len; i++) {
            sqlStr.append(mf.format(new Object[]{i}));
            if (i < len - 1) {
                sqlStr.append(StrUtil.COMMA);
            }
        }
        log.info("批量操作的sql:{}", sqlStr.toString());
        return sqlStr.toString();
    }

    /**
     * 获取执行sql的列名
     * @param object            操作数据集合的第一个元素
     * @return 列名集合
     * @author yzy
     * @date 2022/7/27 14:59
     */
    private <T extends Serializable> List<String> getColumnNames(T object) {
        if (ObjectUtil.isNull(object)) {
            throw new IllegalArgumentException("参数错误,object不能为null");
        }
        Map<String, Object> map = BeanUtil.beanToMap(object, true, false);
        if (CollUtil.isEmpty(map)) {
            throw new BeanException("请检查实体类中的属性和值是否正确");
        }
        // 排除@TableField(exist = false)修饰的属性
        Field[] fields = ReflectUtil.getFields(object.getClass());
        List<String> unExistCols = Arrays.stream(fields)
                .filter(field -> field.isAnnotationPresent(TableField.class) && !field.getAnnotation(TableField.class).exist())
                .map(field -> StrUtil.toUnderlineCase(field.getName())).collect(Collectors.toList());
        for (String unExistCol : unExistCols) {
            map.remove(unExistCol);
        }
        // 排除值为null的属性,id属性是特例不能被排除
        //Set<String> colNameSet = MapUtil.filter(map, (Editor<Map.Entry<String, Object>>) entry -> ObjectUtil.isNull(entry.getValue()) && !StrUtil.equals("id", entry.getKey()) ? null : entry).keySet();
        List<String> keylist = map.entrySet().stream().filter(entry -> ObjectUtil.isNull(entry.getValue()) && !StrUtil.equals("id", entry.getKey())).map(entry -> entry.getKey()).collect(Collectors.toList());
        return keylist;
    }
}
